package com.atguigu.gmall.activity.receiver;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;

import lombok.SneakyThrows;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

@Component
public class SeckillReceiver {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SeckillGoodsService seckillGoodsService;

    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(value = @Queue(
            value = MqConst.QUEUE_TASK_1,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_1}))
    public void importToRedis(Message message, Channel channel){
        try {
            //查询今天要秒杀的商品集合
            QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();
            seckillGoodsQueryWrapper.eq("date_format(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
            seckillGoodsQueryWrapper.eq("status","1");
            //商品剩余数量大于0
            seckillGoodsQueryWrapper.gt("stock_count",0);
            //今天要秒杀的商品集合
            List<SeckillGoods> seckillGoodList = this.seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);
            //判断list集合是否为空
            if (!CollectionUtils.isEmpty(seckillGoodList)){
                //秒杀key
                String seckillKey = RedisConst.SECKILL_GOODS;
                for (SeckillGoods seckillGoods : seckillGoodList) {
                    //如果缓存中存在数据 则需要停止添加 查询缓存中是否有数据
                    Boolean exist = this.redisTemplate.opsForHash().hasKey(seckillKey, seckillGoods.getSkuId().toString());
                    if (exist){
                        //有数据 continue跳过下面的执行语句 然后继续循环
                        continue;
                    }
                    //往缓存里添加数据
                    this.redisTemplate.opsForHash().put(seckillKey,seckillGoods.getSkuId().toString(),seckillGoods);
                    //商品秒杀数量的存储 存储到list队列中 lpush:存 rpop:取
                    for (Integer i = 0; i < seckillGoods.getStockCount() ; i++) {
                        String stockKey = RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId();
                        this.redisTemplate.opsForList().leftPush(stockKey,seckillGoods.getSkuId().toString());
                    }
                    //再初始化的时候向管道发送消息skuId:1
                    this.redisTemplate.convertAndSend("seckillpush",seckillGoods.getSkuId()+":1");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //手动确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(value =@Queue(
            value = MqConst.QUEUE_SECKILL_USER,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = {MqConst.ROUTING_SECKILL_USER}))
    public void seckillOrderUser(UserRecode userRecode,Message message,Channel channel){
        /**
         * 1.判断状态位
         * 2.判断用户是否下过订单
         *       setnx key value
         * 3.减库存 list队列
         *      rpop key
         *      出队失败，说明没有库存，则通知其他兄弟节点，别秒杀
         *      publish seckillpush skuId:0
         * 4.将用户秒杀的商品信息 保存到redis中
         * 5.更新redis - stockCount，mySql - stockCount(剩余数量)
         */
        try {
            if (userRecode!=null){
                //预下单保存数据
                seckillGoodsService.seckillUserOrder(userRecode);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(value = @Queue(
            value = MqConst.QUEUE_SECKILL_STOCK,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_STOCK),
            key = {MqConst.ROUTING_SECKILL_STOCK}))
    public void updateStock(Long skuId,Message message,Channel channel){
        try {
            if (skuId!=null){
                this.seckillGoodsService.updateStock(skuId);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(value = @Queue(
            value = MqConst.QUEUE_TASK_18,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_18}))
    public void clearData(Message message,Channel channel){
        /**
         * 1.查出要清空的数据
         * 2.判断时分秒
         */
        try {
            QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();
            seckillGoodsQueryWrapper.eq("status",1);
            seckillGoodsQueryWrapper.le("end_time",new Date());
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);
            for (SeckillGoods seckillGoods : seckillGoodsList) {
                this.redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId());
                //将数据库中的秒杀商品数据的状态更改为2
                //设置更新数据 有多个秒杀商品时
                //seckillGoods.setStatus("2");
                //this.seckillGoodsMapper.updateById(seckillGoods)
            }
            //清空秒杀商品
            this.redisTemplate.delete(RedisConst.SECKILL_GOODS);
            //有可能预下单数据也存在
            this.redisTemplate.delete(RedisConst.SECKILL_ORDERS);
            //真正的下单数据
            this.redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);

            //将数据库中的秒杀商品数据的状态更改为2
            SeckillGoods seckillGoods = new SeckillGoods();
            seckillGoods.setStatus("2");
            seckillGoods.setUpdateTime(new Date());
            this.seckillGoodsMapper.update(seckillGoods,seckillGoodsQueryWrapper);
        } catch (Exception e) {
            e.printStackTrace();
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}
